// DataSet 2.0
//
// 2009-01-10: 	- Dataset row now contain also:
//
// 			- ``_ds_row_num`` : the current row num
// 			- ``_ds_bg``:	a 0 / 1 value to distinguish odd / even rows
function DataSet ( name, ajax_cgi )
{
	DataSet._instances [ name ] = this;

	this.name = name;

	this.ajax = ajax_cgi;
	this.ajax_req = DataSet.ajax;
	this.num_rows = 0;	// Rows in totale dalla query
	this.rows = {};		// Rows in memoria
	this.len  = 0;		// Numero di rows in memoria
	this.page = 0;		// Pagina corrente
	this.lines_per_page = 10; // Linee per pagina
	this.from_row = 0;
	this.to_row   = 0;
	this.curr_doc = 0;	// Valore ordinale del documento corrente in FulShow
	this.paginator_links = 10;

	this._selected = {};	// lista delle rows selezionate
	this._id_map = {};	// Maps '_ds_id' => row

	this.templates = {
				'table_start'  : '<table border="1" width="100%">',
				'table_end'    : '</table>',
				'table_header' : '',
				'table_footer' : '',
				'table_row'    : '',
				'no_rows'      : 'La ricerca non ha prodotto alcun risultato',
				'prev_page'    : '',
				'next_page'    : '',
				'dash'         : ' - ',
				'next_doc'  : '',
				'prev_doc'  : '',
				'checkbox' : '<input type="checkbox" rel="dataset" onchange="DataSet._checkbox_change(\'%(_name)s\',this.value,this.checked)" id="%(_ds_id)s" value="%(_ds_id)s" %(_checked)s/>'
			 };

	
	this.cbacks = { 
		// Funzione ridefinibile da parte dell'utente per manipolare i dati
		// nel momento che vengono inseriti nell'array del DataSet
		'fill_manip' : null, 
		'prefetch_start' : null,
		'prefetch_end'   : null,
		'fill_start'   : null,
		'fill_prepare' : null, 		// This is called BEFORE the _fill_done() starts
		'fill_end'   : null,
		'show_results' : null,
		'row_manip': null,
		'row_add' : null,		// Callback for each row added
		'write_results' : null,		// Callback to change the writing of results behaviour,
		'generate_id' : null,		// Callback to create an unique id (_ds_id) for the single row
		'selected_change' : null
	};

	// PRIVATE ATTRS
	this._attrs = {};
	this._form_fields = null;	// Campi della ricerca
	this._dest_div = null;
	this._fill_cback = null;

	// ========================================================================================
	// METHODS
	// ========================================================================================

	this._init_paginator = function ()
	{
		if ( ! window [ "Paginator" ] ) return null;

		var p = new Paginator ();

		p.templates [ 'pag-first' ] = "&lt;&lt;&lt;";
		p.templates [ 'pag-first-lnk' ] = "javascript:DataSet.page('" + this.name + "',0)";
		p.templates [ 'pag-last' ] = "&gt;&gt;&gt;";
		p.templates [ 'pag-last-lnk' ] = "javascript:DataSet.page('" + this.name + "',%(_TOT_PAGES)s-1)";
		p.templates [ 'pag-prev' ] = "&lt;";
		p.templates [ 'pag-prev-lnk' ] = "javascript:DataSet.page('" + this.name + "',%(_PREV)s)";
		p.templates [ 'pag-next' ] = '&gt;';
		p.templates [ 'pag-next-lnk' ] = "javascript:DataSet.page('" + this.name + "',%(_CURR_PAGE)s+1)";
		p.templates [ 'pag-pos' ] = '%(_PAGE)s';
		p.templates [ 'pag-pos-lnk' ] = "javascript:DataSet.page('" + this.name + "',%(_NUM)s)";
		p.templates [ 'pag-sep' ] = '|';
		p.templates [ 'pag-link-space' ] = '';

		return p;
	};

	this.paginator = this._init_paginator ();

	// This function sets the fields for the DataSet search
	this.set_fields = function ( fields )
	{
		this._form_fields = fields.clone ();
		this.clear ();
	};

	this.get_fields = function () { return this._form_fields; }

	this.del_field = function ( name ) { delete this._form_fields [ name ]; };

	this.rename_field = function ( old_field_name, new_field_name )
	{
		this._form_fields [ new_field_name ] = this._form_fields [ old_field_name ];
		delete this._form_fields [ old_field_name ];
	};

	this.clear = function ()
	{
		this.page = 0;
		this.num_rows = 0;
		this.from_row = 0;
		this.to_row   = this.lines_per_page;
		this.rows = {};
		this.len = 0;

		if ( this._form_fields )
		{
			this._form_fields [ "_X_START_POINT" ] = 0;
			this._form_fields [ "_X_PAGE" ] = 0;
		}

		this._attrs = {};
	};

	this.fill = function ( fill_callback, err_cback )
	{
		var _obj = this;

		if ( fill_callback ) this._fill_cback = fill_callback;

		if ( ! this._form_fields ) 
		{
			this._fill_cback && this._fill_cback ( this );
			return;
		}

		this._form_fields [ '_X_LINES' ] = this.lines_per_page; 
		this._form_fields [ '_X_PAGE' ] = this.page;

		if ( this.cbacks [ 'fill_start' ] ) this.cbacks [ 'fill_start' ] ( this );

		this.ajax_req ( this.ajax, this._form_fields, function ( vars ) { _obj._fill_done ( vars, _obj._fill_cback ); }, err_cback );
	};

	this._fill_done = function ( vars, cback )
	{
		if ( this.cbacks [ 'fill_prepare' ] )
		{
			vars = this.cbacks [ 'fill_prepare' ] ( this, vars );
		}

		var t, len = parseInt ( vars [ 'lines' ] );

		if ( vars [ '_X_START_POINT' ] )		
			this.from_row = vars [ '_X_START_POINT' ];
		else 
			this.from_row = vars [ 'from_row' ];

		if ( ! this.from_row ) this.from_row = 0;

		for ( t = 0; t < len; t ++ )
		{
			if ( ! vars [ 'row' + t ] ) break;

			vars [ "row" + t ] [ 'ds_name' ] = this.name;

			var row = vars [ 'row' + t ];
			var row_index = parseInt ( row [ '_pos' ], 10 ); // this.from_row + t;

			if ( this.cbacks [ "generate_id" ] ) 
				row [ '_ds_id' ] = String ( this.cbacks [ "generate_id" ] ( this, row ) );
			else
				row [ '_ds_id' ] = this.name + "-" + row [ '_pos' ];

			this._id_map [ row [ '_ds_id' ] ] = row;

			row [ '_name' ] = this.name;

			if ( this.cbacks [ 'fill_manip' ] )
				this.rows [ row_index ] = this.cbacks [ 'fill_manip' ].call ( this, row );
			else
				this.rows [ row_index ] = row;
		}

		// FIXME: forse non serve
		this.to_row = parseInt ( this.from_row, 10 ) + len;

		this.num_rows = vars [ 'rows' ];

		if ( this.cbacks [ 'fill_end' ] ) this.cbacks [ 'fill_end' ] ( this, vars );

		if ( cback ) cback ( this );
	};

	this.needs_prefetch = function ( row_num )
	{
		if ( row_num >= this.num_rows ) row_num = this.num_rows -1;
		if ( row_num < 0 ) return false;
		if ( this.rows [ row_num ] ) return false;

		var start = Math.floor ( row_num / this.lines_per_page ) * this.lines_per_page;
		var end   = start + this.lines_per_page -1;

		if ( end >= this.num_rows ) end = this.num_rows -1;

		if ( ! this.rows [ start ] ) return true;
		if ( ! this.rows [ end ] ) return true;

		return false;
	};

	this.prefetch = function ( num, cback )
	{
		if ( ! this.needs_prefetch ( num ) ) return cback ( this );

		var start = Math.floor ( num / this.lines_per_page ) * this.lines_per_page;

		this._form_fields [ '_X_START_POINT' ] = start;

		if ( this.cbacks [ 'prefetch_start' ] ) this.cbacks [ 'prefetch_start' ] ( this );

		this.fill ( cback );

		return true;
	};


	this.get_row = function ( num )
	{
		var row;

		if ( num >= this.num_rows ) return null;

		row = this.rows [ num ];

		return row;
	};

	this.filter_date = function ( s )
	{
		var g = parseInt ( s.replace ( /[^0-9]*([0-9][0-9]*)-([0-9][0-9]*)-([0-9][0-9][0-9][0-9]).*/, "$1" ), 10 );
		var m = parseInt ( s.replace ( /[^0-9]*([0-9][0-9]*)-([0-9][0-9]*)-([0-9][0-9][0-9][0-9]).*/, "$2" ), 10 );
		var a = s.replace ( /.*([0-9][0-9]*)-([0-9][0-9]*)-([0-9][0-9][0-9][0-9]).*/, "$3" );
		var pre = s.replace ( /([^0-9]*)[0-9][0-9]*-[0-9][0-9]*-[0-9][0-9][0-9][0-9].*/, "$1" );
		var post = s.replace ( /.*[0-9][0-9]*-[0-9][0-9]*-[0-9][0-9][0-9][0-9](.*)/, "$1" );

		if ( g < 10 ) g = "0" + g;
		if ( m < 10 ) m = "0" + m;

		return pre + g + "/" + m + "/" + a + post;
	};

	this.render = function ( dest_div, render_cback )
	{
		var _obj = this;

		if ( ! dest_div ) dest_div = this._dest_div;
		this._dest_div = dest_div;

		this.prefetch ( this.from_row, function ( ds ) { _obj._render_done ( dest_div, render_cback ); } );
	};

	this._render_done = function ( dest_div, render_cback )
	{
		var s = '';

		this._prepare_pagination ();

		s = this.to_string ();

		if ( this.cbacks [ 'write_results' ] )
			this.cbacks [ 'write_results' ] ( s );
		else
			$( dest_div, s );

		if ( ! render_cback ) render_cback = this.cbacks [ 'show_results' ];
		if ( render_cback ) render_cback ( this );
	};

	this.refresh = function ( cback )
	{
		this._form_fields [ '_X_START_POINT' ] = this.from_row;
		this.fill ( cback, true );
	};

	this.to_string = function ()
	{
		var s = new String.buffer ();
		var t, row;
		var tmp;

		if ( this.num_rows == 0 )
			return String.formatDict ( this.templates [ 'no_rows' ], this._attrs );

		s.add ( String.formatDict ( this.templates [ 'table_start' ], this._attrs ) );
		s.add ( String.formatDict ( this.templates [ 'table_header' ], this._attrs ) );

		// Ho messo <= in 'to_row' perche' altrimenti salta la prima riga
		// for ( t = 0; t < this.len; t ++ )
		for ( t = this.from_row; t < this.to_row ; t ++ )
		{
			row = this.get_row ( t ); 

			if ( ! row ) continue;

			if ( t > this.num_rows ) break;

			row [ 'ds_name' ] = this.name;
			row [ '_ds_row_num' ] = t;
			row [ '_ds_bg' ] = t % 2;

			if ( this._selected [ row [ '_ds_id' ] ] )
				row [ '_checked' ] = 'checked="checked"';
			else
				row [ '_checked' ] = '';

			row [ '_checkbox' ] = String.formatDict ( this.templates [ 'checkbox' ], row );

			this.cbacks [ "row_manip" ] && this.cbacks [ "row_manip" ] ( this, row );

			tmp = String.formatDict ( this.templates [ 'table_row' ], row );

			s.add ( tmp );

			// Nuova callback che aggiunge una singola riga gia' elaborata
			this.cbacks.row_add && this.cbacks.row_add ( tmp );

			delete row [ '_checkbox' ];
			delete row [ '_checked' ];
		}

		s.add ( String.formatDict ( this.templates [ 'table_footer' ], this._attrs ) );
		s.add ( String.formatDict ( this.templates [ 'table_end' ], this._attrs ) );

		return s.toString ();
	};

	this._prepare_pagination = function ()
	{
		var delta    = this.to_row - this.from_row;
		var res, to_row, num_rows;

		res = this.from_row + 1;
		to_row = this.to_row;
		num_rows = this.num_rows;

		if ( to_row > num_rows ) to_row = num_rows;

		if ( num_rows <= this.lines_per_page )
			this._attrs [ 'docs_shown' ] = to_row;
		else
			this._attrs [ 'docs_shown' ] = res + " - " + to_row + " di " + num_rows;

		this._attrs [ 'from_row' ] = res;
		this._attrs [ 'to_row' ] = to_row;
		this._attrs [ 'num_rows' ] = num_rows;
		this._attrs [ '_name' ] = this.name;
		this._attrs [ '_prev_page' ] = null;
		this._attrs [ '_next_page' ] = null;
		this._attrs [ 'prev_page' ] = "&nbsp;";
		this._attrs [ 'next_page' ] = "&nbsp;";
		this._attrs [ 'dash' ] = "";
		this._attrs [ 'paginator' ] = "";

		if ( this.paginator )
		{
			this.paginator.init ( this.num_rows, this.lines_per_page, this.paginator_links );
			this.paginator.set_page ( this.page );
		}

		if ( num_rows <= this.lines_per_page ) return;

		if ( this.page ) 
			this._attrs [ '_prev_page' ] = "javascript:DataSet.page('" + this.name + "'," + ( this.page -1 ) +")";

		if ( this.to_row < this.num_rows )
			this._attrs [ '_next_page' ] = "javascript:DataSet.page('" + this.name + "'," + ( this.page +1 ) + ")";

		if ( this._attrs [ '_prev_page' ] )
			this._attrs [ 'prev_page' ] = String.formatDict ( this.templates [ 'prev_page' ], this._attrs );

		if ( this._attrs [ '_next_page' ] )
			this._attrs [ 'next_page' ] = String.formatDict ( this.templates [ 'next_page' ], this._attrs );

		if ( this.page && ( this.to_row < this.num_rows ) )
			this._attrs [ 'dash' ] = this.templates [ "dash" ];

		if ( this.paginator )
		{
			this._attrs [ "paginator" ] = this.paginator.mk_str ();
		} else
			this._attrs [ "paginator" ] = "Include paginator.js";
	};

	this.show_page = function ( page )
	{
		this.page = page;

		this.from_row = this.lines_per_page * page;
		this.to_row = this.lines_per_page * ( page +1 );

		this.render ();
	};

	this.format_str = function ( template )
	{
		return String.formatDict ( template, this._attrs );
	};

	this.set_curr_doc   = function ( pos ) { 
		if ( pos === undefined ) pos = -1;
		this.curr_doc = pos; 
	};

	this.prepare_result_navi = function ( cback )
	{
		var _obj = this;

		if ( this.curr_doc == -1 ) return;

		this.prefetch ( this.curr_doc + 2, function ( ds ) { _obj.result_navi ( ds, cback ); } );
	};

	this.result_navi = function ( ds, cback )
	{
		if ( this._form_fields && this.needs_prefetch ( this.curr_doc +2 ) ) 
		{
			var _obj = this;
			this.prefetch ( this.curr_doc +2, function ( ds ) { _obj.result_navi ( ds, cback ); } );
			return;
		}

		var s = '';
		var row;
		
		if ( this.curr_doc > 0 )
		{
			// Posso tornare indiretro
			row = this.rows [ this.curr_doc -1 ];
			this._attrs [ 'prev_doc' ] = String.formatDict ( this.templates [ 'prev_doc' ], row );

			// 'javascript:DataSet.doc(\'' + this.name + '\',\'' + row.get ( 'id' ) + '\',{pos: ' + ( this.curr_doc -1 ) + '})';
		} else
			this._attrs [ 'prev_doc' ] = null;

		if ( this.curr_doc < this.num_rows -1 )
		{
			// Posso andare avanti
			row = this.rows [ this.curr_doc +1 ];
			this._attrs [ 'next_doc' ] = String.formatDict ( this.templates [ 'next_doc' ], row );
			// this._attrs [ 'next_doc' ] = 'javascript:DataSet.doc(\'' + this.name + '\',\'' + row.get ( 'id' ) + '\',{pos: ' + ( this.curr_doc +1 ) + '})';
		} else
			this._attrs [ 'next_doc' ] = null;

		if ( cback ) cback ( ds );
	};

	this.set_selected = function ( ds_id, checked )
	{
		ds_id = String ( ds_id );

		if ( ! checked )
			delete this._selected [ ds_id ];
		else
			this._selected [ ds_id ] = this._id_map [ ds_id ];

		if ( this.cbacks [ 'selected_change' ] ) this.cbacks [ 'selected_change' ] ( this );
	};

	this.get_selected = function ()
	{
		var res = [];
		var self = this;
		
		this._selected.iterate ( function ( row )
		{
			res.push ( row );
		} );
		
		return res;
	};
	
	this.clear_selected = function ()
	{
		this._selected = {};		
	};

	this.select_all = function ( selected )
	{
		var self = this;

		this._id_map.iterate ( function ( v, k )
		{
			$( k ).checked = selected;
			self.set_selected ( k, selected );
		} );
	};
}

DataSet._instances = {};

DataSet.get = function ( instance_name )
{
	return DataSet._instances [ instance_name ];
};

DataSet._checkbox_change = function ( ds_name, value, checked )
{
	var ds = DataSet.get ( ds_name );

	// FIXME: forse qui ci andrebbe la cback di generate
	ds.set_selected ( value, checked );
};

DataSet.page = function ( name, page_no )
{
	var ds = DataSet._instances [ name ];

	ds.show_page ( page_no );
};

DataSet.ajax = function ( ajax, fields, cback, err_cback ) { liwe.AJAX.request ( ajax, fields, cback, true, false, err_cback ); };

DataSet.select_all = function ( name, selected )
{
	var ds = DataSet._instances [ name ];

	ds.select_all ( selected );
};
